//Features as per Andres' WACV paper

inline
features_UCF11::features_UCF11(const std::string in_path, const std::string  in_actionNames, const std::string  in_viNames, 
			       const std::string  in_viList, const int in_col, const int in_row)
:path(in_path), actionNames(in_actionNames), viNames(in_viNames), viList(in_viList), col(in_col), row(in_row)
{
  
}

inline
void
features_UCF11::start_features()
{
  
  std::stringstream tmp_ss;
  tmp_ss << path << actionNames;
  actions.load(tmp_ss.str());
  actions.print("All actions");
  
  //actions.n_rows;
  for (uword act = 0 ; act < actions.n_rows; ++act) {
    feature_actiongroup(act);
  }
  
}

inline
void
features_UCF11::feature_actiongroup(uword act){
  
  std::stringstream tmp_ss2;
  tmp_ss2 << path << actions(act) << viNames;
  vigroup.load(tmp_ss2.str());
  
  //vigroup.n_rows
  for(uword vg = 0 ; vg< vigroup.n_rows; ++vg) {
    std::stringstream tmp_ss3;
    tmp_ss3 << path << actions(act) << vigroup(vg) << viList;
    cout << tmp_ss3.str() << endl;
    vilist.load(tmp_ss3.str());
    vilist.print("List in this folder");
    
    // vilist.n_rows;
    fea_group.set_size(vilist.n_rows);
    
    for ( uword l = 0; l<vilist.n_rows; ++l ){
      std::stringstream tmp_ss4;
      tmp_ss4 << path << actions(act) << vigroup(vg) << vilist(l);
      cout << vilist(l) << endl;
      fea_group(l)= feature_video(tmp_ss4.str());
    }
    std::string gname = vigroup(vg);
    
    std::string gname2 =  gname.substr(0, gname.size()-1);
    cout << vigroup(vg) << endl;
    cout << gname2 << endl;
    std::stringstream saving_group;
    saving_group << "./optiflow_features/" << gname2;
    cout << "Saving..." << endl;
    fea_group.save(saving_group.str());
    //getchar();
  }
  
 
}



inline 
mat
features_UCF11::feature_video(std::string one_video)
{
  cv::VideoCapture capVideo(one_video);
  //cout << one_video << endl;
  //double fps = capVideo.get(CV_CAP_PROP_FPS); //get the frames per seconds of the video
  //cout << "Frame per seconds : " << fps << endl;
  
  //cv::namedWindow("MyVideo",CV_WINDOW_AUTOSIZE); //create a window called "MyVideo"
  //double frmcount = capVideo.get(CV_CAP_PROP_FRAME_COUNT);
  //cout << "# of frames is: " << frmcount << endl;
  
  if( !capVideo.isOpened() )
  {
    cout << "Video couldn't be opened" << endl;
    return 0;
  }
  
  cv::Mat prevgray, gray, flow, cflow, frame, prevflow;
  cv::Mat ixMat, iyMat, ixxMat, iyyMat;
  //cv::namedWindow("My Video", 1);
  running_stat_vec<vec> stats_video(true);
  int t = 0;
  for(;;){
    //capVideo >> frame;
    
    bool bSuccess = capVideo.read(frame); // read a new frame from video
    
    if (!bSuccess) //if not success, break loop
	{
	  //cout << "Cannot read the frame from video file" << endl;
	  break;
	}
	t++;
    cv::cvtColor(frame, gray, CV_BGR2GRAY);
    //cv::imshow("My Video", frame);
    //getchar();
    if( prevgray.data )
    {
      //cout << "Cuando entra aca?? en t= " << t << endl;
      cv::calcOpticalFlowFarneback(prevgray, 
				   gray, 
				   flow, 
				   0.5, //pyr_scale
				   3,   //levels
				   8,   //winsize
				   3,   //iterations
				   5,   //poly_n
				   1.1, //poly_sigma
				   0);  //flags
      //cv::calcOpticalFlowFarneback(bl_currentImg, bl_nextImg, flow, 0.5,  3, 5, 3, 5, 1.2, 0); 
      //cv::cvtColor(prevgray, cflow, CV_GRAY2BGR);
      //drawOptFlowMap(flow, cflow, 8, 1.5, CV_RGB(0, 255, 0));
      //cv::imshow("flow", cflow);
      
      
      cv::Sobel(gray, ixMat, CV_32F, 1, 0, 1);
      cv::Sobel(gray, iyMat, CV_32F, 0, 1, 1);
      cv::Sobel(gray, ixxMat, CV_32F, 2, 0, 1);
      cv::Sobel(gray, iyyMat, CV_32F, 0, 2, 1);
      
      float  ux = 0, uy = 0, vx = 0,  vy = 0;
      float u, v;
      //cout << "Llega a ciclo de Pixels???" << endl;
      //cout << "col: " << col << "- row " << row << endl;
      if( prevflow.data )
      {
	for (uword x = 0 ; x < col ; ++x ){
	  for (uword y = 0 ; y < row ; ++y ) {
	    
	    vec features_one_pixel(15); 
	    u = flow.at<cv::Vec2f>(y, x)[0];
	    v = flow.at<cv::Vec2f>(y, x)[1];
	    
	    //cout << "x= " << x << " - y= " << y << endl;
	    // x grad
	    //cout << " x y grad" << endl;
	    float ix = ixMat.at<float>(y, x);
	    //cout << " y grad" << endl;
	    float iy = iyMat.at<float>(y, x);
	    
	    // grad direction &  grad magnitude
	    //cout << "grad direction &  grad magnitude" << endl;
	    float gd = std::atan2(std::abs(iy), std::abs(ix));
	    float gm = std::sqrt(ix * ix + iy * iy);
	    
	    // x second grad
	    //cout << "x y  second grad " << endl;
	    float ixx = ixxMat.at<float>(y, x);
	    // y second grad
	    float iyy = iyyMat.at<float>(y, x);
	    
	    //du/dt
	    float ut = u - prevflow.at<cv::Vec2f>(y, x)[0];
	    // dv/dt
	    float vt = v - prevflow.at<cv::Vec2f>(y, x)[1];
	    
	    //// divergence &  vorticity
	    //cout << "divergence &  vorticity" << endl;
	    if (x>0 && y>0 )
	    {
	      ux = u - flow.at<cv::Vec2f>(y, x - 1)[0];
	      uy = u - flow.at<cv::Vec2f>(y - 1, x)[0];
	      vx = v - flow.at<cv::Vec2f>(y, x - 1)[1];
	      vy = v - flow.at<cv::Vec2f>(y - 1, x)[1];
	    }
	    
	    //int x_submat = x + rec.x;
	    //int y_submat = y + rec.y;
	    //cout << x_submat << "&" << y_submat << endl;
	    
	    features_one_pixel  << x << y << t << abs(ix) << abs(iy) << abs(ixx) 
	    << abs(iyy) << gm << gd <<  u << v << abs(ut) 
	    << abs(ut) << (ux - vy)  << (vx - uy);
	    //features_one_pixel.t().print("Features Current Pixel: ");
	    //getchar();
	    if (!is_finite( features_one_pixel ) )
	    {
	      cout << "It's not FINITE... continue???" << endl;
	     getchar(); 
	    }
	    stats_video(features_one_pixel);
	    //cout << stats_video.cov() << endl;
	    //cout << stats_video.mean() << endl;
	  }
	}
      }
    }
    if(cv::waitKey(30)>=0)
      break;
    //cout << "t: " <<t << endl;
    std::swap(prevgray, gray);
    std::swap(prevflow, flow);//aca esta el problema.... cuando hay flow????
  } 
  
  //cout << "End Video " << endl << endl;
  
  mat cov = stats_video.cov();
  //cout << "covariance matrix size [ " << cov.n_rows << " x " << cov.n_cols << " ] " << endl;
  //cout << stats_video.cov() << endl;
  //getchar();
  return cov;
}



inline
void 
features_UCF11::drawOptFlowMap(const cv::Mat& flow, cv::Mat& cflowmap, int step, double, const cv::Scalar& color)
{
  for(int y = 0; y < cflowmap.rows; y += step)
    for(int x = 0; x < cflowmap.cols; x += step)
    {
      const cv::Point2f& fxy = flow.at<cv::Point2f>(y, x);
      cv::line(cflowmap, cv::Point(x,y), cv::Point(cvRound(x+fxy.x), cvRound(y+fxy.y)), color);
      cv::circle(cflowmap, cv::Point(x,y), 2, color, -1);
    }
}

